package classfile

import "fmt"

type ClassFile struct {
				   //magic      uint32 //魔数
	minorVersion uint16        //次版本号
	majorVersion uint16        //主版本号
	constantPool ConstantPool  //常量池(Map结构，其中含有<classIndex,类名>)
	accessFlags  uint16        //访问标记(是类还是接口，是public还是private)
	thisClass    uint16        //当前类索引
	superClass   uint16        //父类索引
	interfaces   []uint16      //接口索引表
	fields       []*MemberInfo //字段表
	methods      []*MemberInfo //方法表
	attributes   []AttributeInfo
}

/**
包方法
 */
func Parse(classDate []byte) (cf *ClassFile, err error) {
	defer func() {
		if er := recover(); er != nil {
			var ok bool
			err, ok = er.(error)
			if !ok {
				err = fmt.Errorf("%v", er) //抛出异常
			}
		}
	}()

	cr := &ClassReader{classDate}
	cf := &ClassFile{}
	cf.read(cr)
	return
}

func (self *ClassFile) read(reader *ClassReader) {
	self.readAndCheckMagic(reader)
	self.readAndCheckVersion(reader)
	self.constantPool = readConstantPool(reader)
	self.accessFlags = reader.readUint16()
	self.thisClass = reader.readUint16()
	self.superClass = reader.readUint16()
	self.interfaces = reader.readUint16s()
	self.fields = readMembers(reader, self.constantPool)
	self.methods = readMembers(reader, self.constantPool)
	self.attributes = readAttributes(reader, self.constantPool)
}

//检查魔数
func (self *ClassFile)readAndCheckMagic(reader *ClassReader) {
	magic := reader.readUint32() //读取4个字节
	if magic != 0xCAFEBABE {
		panic("java.lang.ClassFormatError:magic!")
	}
}
//仅支持45-52的版本号
func (self *ClassFile)readAndCheckVersion(reader *ClassReader) {
	self.minorVersion = reader.readUint16()
	self.majorVersion = reader.readUint16()

	switch self.majorVersion {
	case 45:
		return
	case 46, 47, 48, 49, 50, 51, 52:
		if self.minorVersion == 0 {
			return
		}
	}
	panic("java.lang.UnsupportedClassVersionError!")
}



/**
Get 方法
 */
func (self *ClassFile) MinorVersion() uint16 {
	return self.minorVersion
}
func (self *ClassFile) MajorVersion() uint16 {
	return self.majorVersion
}
func (self *ClassFile) ConstantPool() ConstantPool {
	return self.constantPool
}
func (self *ClassFile) AccessFlags() uint16 {
	return self.accessFlags
}
func (self *ClassFile) Fields() []*MemberInfo {
	return self.fields
}
func (self *ClassFile) Methods() []*MemberInfo {
	return self.methods
}

func (self *ClassFile) ClassName() string {
	return self.constantPool.getClassName(self.thisClass)
}

func (self *ClassFile) SuperClassName() string {
	if self.superClass > 0 {
		return self.constantPool.getClassName(self.superClass)
	}
	return ""
}

func (self *ClassFile) InterfaceNames() []string {
	interfaceNames := make([]string, len(self.interfaces))
	for i, cpIndex := range self.interfaces {
		interfaceNames[i] = self.constantPool.getClassName(cpIndex)
	}
	return interfaceNames
}

